package com.hiwan.system.util;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.method.HandlerMethod;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hiwan.platform.util.ThreadExecutorHelper;
import com.hiwan.platform.utils.DateUtils;
import com.hiwan.platform.utils.Exceptions;
import com.hiwan.platform.utils.SpringContextHolder;
import com.hiwan.platform.utils.StringUtils;
import com.hiwan.system.dao.log.LogDao;
import com.hiwan.system.dao.menu.MenuDao;
import com.hiwan.system.pojo.Log;
import com.hiwan.system.pojo.MenuInfo;
import com.hiwan.system.pojo.UserInfo;

/**
 * 
 * Datetime   ： 2016年1月5日 下午8:57:42<br>
 * Title      :  LogUtils.java<br>
 * Description:   日志工具类<br>
 * Company    :  hiwan<br>
 * @author cbj
 *
 */
public class LogUtils {
	
	public static final String CACHE_MENU_NAME_PATH_MAP = "menuNamePathMap";
	
	private static LogDao logDao = SpringContextHolder.getBean(LogDao.class);
	private static MenuDao menuDao = SpringContextHolder.getBean(MenuDao.class);
	
	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request, String title){
		saveLog(request, null, null, title);
	}
	
	
	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request,Throwable ex,String title){
		saveLog(request, null, ex, title);
	}
	
	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request, Object handler, Throwable ex, String title){
		UserInfo user = UserCacheUtils.getUser();
		if (user != null && user.getUserId() != null){
			Log log = new Log();
			log.setId(IdGen.uuid());
			log.setTitle(title);
			log.setType(ex == null ? Log.TYPE_ACCESS : Log.TYPE_EXCEPTION);
			log.setRemoteAddr(StringUtils.getRemoteAddr(request));
			log.setUserAgent(request.getHeader("user-agent"));
			log.setRequestUri(request.getRequestURI());
			log.setRequestMethod(request.getMethod());
			log.setCreateBy(user.getUserId());
			log.setCreateDate(DateUtils.getDate());
			
			// 异步保存日志
			new SaveLogThread(0,log,handler,ex).execute();
		}
	}
	
	/**
	 * 保存日志线程
	 */
	public static class SaveLogThread extends ThreadExecutorHelper{
		
		private Log log;
		private Object handler;
		private Throwable ex;

		public SaveLogThread(int reTryCount,Log log, Object handler, Throwable ex){
			super(reTryCount);
			this.log = log;
			this.handler = handler;
			this.ex = ex;
		}
		
		@Override
		public void doJob() {
			// 获取日志标题
			if (StringUtils.isBlank(log.getTitle())){
				String permission = "";
				if (handler instanceof HandlerMethod){
					Method m = ((HandlerMethod)handler).getMethod();
					RequiresPermissions rp = m.getAnnotation(RequiresPermissions.class);
					permission = (rp != null ? StringUtils.join(rp.value(), ",") : "");
				}
				log.setTitle(getMenuNamePath(log.getRequestUri(), permission));
			}
			// 如果有异常，设置异常信息
			log.setException(Exceptions.getStackTraceAsString(ex));
			// 如果无标题并无异常日志，则不保存信息
			if (StringUtils.isBlank(log.getTitle()) && StringUtils.isBlank(log.getException())){
				return;
			}
			//logDao.insert(log);
		}

		@Override
		public void doException(Throwable e) {
			logger.error("保存日志失败：日志【{}】，重试次数【{}】",log,getReTryCount());
		}
	}

	/**
	 * 获取菜单名称路径（如：系统设置-机构用户-用户管理-编辑）
	 */
	public static String getMenuNamePath(String requestUri, String permission){
		String href = StringUtils.substringAfter(requestUri, "");
		@SuppressWarnings("unchecked")
		Map<String, String> menuMap = (Map<String, String>)CacheUtils.get(CACHE_MENU_NAME_PATH_MAP);
		if (menuMap == null){
			menuMap = Maps.newHashMap();
			//List<MenuInfo> menuList = menuDao.findAllList(new MenuInfo());
			List<MenuInfo> menuList = menuDao.selectAllMenusInfo("");
			for (MenuInfo menu : menuList){
				// 获取菜单名称路径（如：系统设置-机构用户-用户管理-编辑）
				String namePath = null;
				if (menu.getSubMenus() != null){
					List<String> namePathList = Lists.newArrayList();
					namePathList.add(menu.getMenuName());
					for (MenuInfo subMenu : menu.getSubMenus()){
						namePathList.add(subMenu.getMenuName());
					}
					namePath = StringUtils.join(namePathList, "-");
				}
				// 设置菜单名称路径
				if (StringUtils.isNotBlank(menu.getMenuUrl())){
					menuMap.put(menu.getMenuUrl(), namePath);
				}else if (StringUtils.isNotBlank(menu.getPermission())){
					for (String p : StringUtils.split(menu.getPermission())){
						menuMap.put(p, namePath);
					}
				}
				
			}
			CacheUtils.put(CACHE_MENU_NAME_PATH_MAP, menuMap);
		}
		String menuNamePath = menuMap.get(href);
		if (menuNamePath == null){
			for (String p : StringUtils.split(permission)){
				menuNamePath = menuMap.get(p);
				if (StringUtils.isNotBlank(menuNamePath)){
					break;
				}
			}
			if (menuNamePath == null){
				return "testtesttest";
			}
		}
		return menuNamePath;
	}

	
}
